//
//  QRCodeScanView.m
//  QRCodeScanDemo
//
//  Created by nav on 2017/5/16.
//  Copyright © 2017年 nav. All rights reserved.
//

#import "QRCodeScanView.h"
#import <AVFoundation/AVFoundation.h>

@implementation ScanButton

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
        [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        self.titleLabel.font = [UIFont systemFontOfSize:12];
        self.titleLabel.textAlignment = NSTextAlignmentCenter;
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.imageView.frame = CGRectMake((self.frame.size.width - 30)/2, 0, 30, 30);
    self.titleLabel.frame = CGRectMake(0, 30, self.frame.size.width, self.frame.size.height - 30);
}

@end


#define BootomViewHeight 140 //条形码底部的控件部分高度(包括扫描说明,按钮)
#define InPutAndLightBtnWidth 120  //手动输入按钮和开关灯按钮的宽度
#define InPutAndLightBtnHeight 60  //手动输入按钮和开关灯按钮的高度
#define LightBtnMarginInputBtn 20  //手动输入按钮和开关灯按钮之间的距离

@interface QRCodeScanView()<AVCaptureMetadataOutputObjectsDelegate>
@property (nonatomic, copy) ScanCompletionResult result;
@property (nonatomic, copy) InputButtonAction inputAction;
@property (nonatomic, strong) AVCaptureDevice *device;
@property (nonatomic, strong) AVCaptureDeviceInput *deviceInput;
@property (nonatomic, strong) AVCaptureMetadataOutput *dataOutput;
@property (nonatomic, strong) AVCaptureSession *session;
@property (nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
@property (nonatomic, strong) UIView *maskView; //蒙版
@property (nonatomic, strong) UIImageView *scanImageView; //扫描边框的背景图片
@property (nonatomic, strong) UIImageView *scanLineImageView; //扫描动画的线条
@property (nonatomic, assign) CGRect scanRect;//扫描区域的frame
@property (nonatomic, weak) ScanButton *recordBtn;
@property (nonatomic, weak) UILabel *tipLabel;
@property (nonatomic, assign) BOOL isShowLightBtn;
@property (nonatomic, assign) BOOL isShowInputBtn;
@property (nonatomic, copy) NSString *inputBtnTitle;
@property (nonatomic, copy) NSString *tipMsg;
@end

@implementation QRCodeScanView

#pragma mark - 开始扫描
- (void)startScan {
    if (![self authorizationCheck]) {
        return;
    }
    [self scanLineAnimation];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if (![self.session isRunning]) {
            [self.session startRunning];
        }
    });
}

#pragma mark - 结束扫描
- (void)stopScan {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
        if ([self.session isRunning]) {
            [self.session stopRunning];
        }
    });
    [self removeScanLineAnimation];
}


+ (instancetype)showScanQRCodeWithFrame:(CGRect)scanFrame
                         isShowLightBtn:(BOOL)isShowLightBtn
                         isShowInputBtn:(BOOL)isShowInputBtn
                             completion:(ScanCompletionResult)completion
                       clickInputButton:(InputButtonAction)clickInputButton {
    return [[self alloc] initWithFrame:scanFrame isShowLightBtn:isShowLightBtn isShowInputBtn:isShowInputBtn completion:completion clickInputButton:clickInputButton];
}

- (instancetype)initWithFrame:(CGRect)frame
               isShowLightBtn:(BOOL)isShowLightBtn
               isShowInputBtn:(BOOL)isShowInputBtn
                   completion:(ScanCompletionResult)completion
             clickInputButton:(InputButtonAction)clickInputButton
                {
    self = [super init];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.frame = frame;
        _result = [completion copy];
        _isShowLightBtn = isShowLightBtn;
        _isShowInputBtn = isShowInputBtn;
        _inputAction = [clickInputButton copy];
        CGSize scanSize = CGSizeMake(self.frame.size.width * 3/4, self.frame.size.width * 3/4);
        _scanRect = CGRectMake((self.frame.size.width - scanSize.width)/2, (self.frame.size.height - scanSize.height - BootomViewHeight)/2, scanSize.width, scanSize.height);
        [self installUI];
    }
    return self;
}


#pragma mark - 初始化UI
- (void)installUI {
    [self addSubview:self.scanImageView];
    [self addSubview:self.scanLineImageView];
    [self addSubview:self.maskView];
    [self setupSession];
    [self initializeBottomViews];
}

//初始化底部的控件
- (void)initializeBottomViews {
    
    CGFloat marginTop = (self.frame.size.height - self.scanRect.size.height - BootomViewHeight )/2 + self.scanRect.size.height;
    
    UILabel *tipLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, marginTop+10, [UIScreen mainScreen].bounds.size.width, 20)];
    tipLabel.backgroundColor = [UIColor clearColor];
    tipLabel.textColor = [UIColor whiteColor];
    tipLabel.text = @"将二维码/条码放入框内,即可自动扫描";
    tipLabel.textAlignment = NSTextAlignmentCenter;
    tipLabel.font = [UIFont systemFontOfSize:13];
    self.tipLabel = tipLabel;
    [self addSubview:tipLabel];
    
    //手动输入button
    ScanButton *inputBtn = [ScanButton buttonWithType:UIButtonTypeCustom];
    self.recordBtn = inputBtn;
    [inputBtn setImage:[self imageWithName:@"icon_enterinput"] forState:UIControlStateHighlighted];
    [inputBtn setImage:[self imageWithName:@"icon_enterinput"] forState:UIControlStateNormal];
    [inputBtn addTarget:self action:@selector(inputBtnEvent:) forControlEvents:UIControlEventTouchUpInside];

    if (self.isShowLightBtn && self.isShowInputBtn) { //两个按钮
       inputBtn.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width - LightBtnMarginInputBtn - 2*InPutAndLightBtnWidth) * 0.5, marginTop + 45, InPutAndLightBtnWidth, InPutAndLightBtnHeight);
        //开关灯button
        ScanButton *turnBtn = [ScanButton buttonWithType:UIButtonTypeCustom];
        turnBtn.frame = CGRectMake(CGRectGetMaxX(inputBtn.frame) + LightBtnMarginInputBtn, marginTop + 45, InPutAndLightBtnWidth, InPutAndLightBtnHeight);
        [turnBtn setImage:[self imageWithName:@"icon_light_normal"] forState:UIControlStateNormal];
        [turnBtn setImage:[self imageWithName:@"icon_light_selected"] forState:UIControlStateSelected];
        [turnBtn setTitle:@"打开手电筒" forState:UIControlStateNormal];
        [turnBtn setTitle:@"关闭手电筒" forState:UIControlStateSelected];
        [turnBtn addTarget:self action:@selector(turnBtnEvent:) forControlEvents:UIControlEventTouchUpInside];
        [inputBtn setTitle:@"手动输入" forState:UIControlStateNormal];
        [inputBtn setTitle:@"手动输入" forState:UIControlStateHighlighted];
      
        [self addSubview:inputBtn];
        [self addSubview:turnBtn];
        
    }else if (self.isShowInputBtn && !self.isShowLightBtn){
        //显示一个按钮
        inputBtn.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width - InPutAndLightBtnWidth) * 0.5, marginTop + 45, InPutAndLightBtnWidth, InPutAndLightBtnHeight);
        [inputBtn setTitle:@"手动输入" forState:UIControlStateNormal];
        [inputBtn setTitle:@"手动输入" forState:UIControlStateHighlighted];
        [self addSubview:inputBtn];
    }else if (!self.isShowInputBtn && !self.isShowLightBtn) {
        //两个按钮都不显示
    }
}

#pragma mark - 点击手动输入按钮
- (void)inputBtnEvent:(UIButton *)sender {
    if (self.inputAction) {
        self.inputAction();
    }
}

- (void)turnBtnEvent:(UIButton *)sender
{
    sender.selected = !sender.selected;
    if (sender.selected) {
        [self turnTorchOn:YES];
    }
    else
    {
        [self turnTorchOn:NO];
    }
}

- (void)turnTorchOn:(bool)on
{
    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");
    if (captureDeviceClass != nil) {
        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        
        if ([device hasTorch] && [device hasFlash]){
            
            [device lockForConfiguration:nil];
            if (on) {
                [device setTorchMode:AVCaptureTorchModeOn];
                [device setFlashMode:AVCaptureFlashModeOn];
                
            } else {
                [device setTorchMode:AVCaptureTorchModeOff];
                [device setFlashMode:AVCaptureFlashModeOff];
            }
            [device unlockForConfiguration];
        }
    }
}

#pragma mark - 初始化会话
- (void)setupSession {

    [self authorizationCheck];

    //获取摄像设备
    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError *error;
    
    //创建输入流
    self.deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
    if (error) {
        NSLog(@"%@",error);
    }
    
    //创建输出流
    self.dataOutput = [[AVCaptureMetadataOutput alloc] init];
    [self.dataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
   
    
    self.session = [[AVCaptureSession alloc] init];
    
    if ([self.device supportsAVCaptureSessionPreset:AVCaptureSessionPreset1920x1080]) {
        [self.session setSessionPreset:AVCaptureSessionPreset1920x1080];
    }
    else
    {
        [self.session setSessionPreset:AVCaptureSessionPresetHigh];
    }
    
    //  拍摄会话 - 判断能够添加设备
    if (![self.session canAddInput:self.deviceInput]){
        NSLog(@"无法添加输入设备deviceInput");
        self.session = nil;
        return;
    }
    
    if (![self.session canAddOutput:self.dataOutput]){
        NSLog(@"无法添加输入设备dataOutput");
        self.session = nil;
        return;
    }
    
    // 添加输入／输出设备
    [self.session addOutput:self.dataOutput];
    [self.session addInput:self.deviceInput];

    self.dataOutput.metadataObjectTypes = self.dataOutput.availableMetadataObjectTypes;
    
    self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    self.previewLayer.frame = self.frame;
    [self.layer insertSublayer:self.previewLayer atIndex:0];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        if (![self.session isRunning]) {
            [self.session startRunning];
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            self.dataOutput.rectOfInterest = [self.previewLayer metadataOutputRectOfInterestForRect:self.scanRect];
        });
    });
    

    //放大焦距
    [self.device lockForConfiguration:&error];
    if (self.device.activeFormat.videoMaxZoomFactor > 2) {
        self.device.videoZoomFactor = 1.5;
    }else{
        self.device.videoZoomFactor = self.device.activeFormat.videoMaxZoomFactor;
    }
    [self.device unlockForConfiguration];
    
    //开始扫描
    [self startScan];
}

#pragma mark - 设置扫描区域
- (CGRect)getScanCrop
{
    CGFloat x,y,width,height;
    x = self.scanRect.origin.y /CGRectGetHeight(self.frame);
    y = self.scanRect.origin.x /CGRectGetWidth(self.frame);
    width = (self.scanRect.size.width + 60) /CGRectGetHeight(self.frame);
    height = (self.scanRect.size.height + 80) /CGRectGetWidth(self.frame);
    return CGRectMake(x, y, width, height);
}

#pragma mark - 扫描线动画
//添加扫描线动画
- (void)scanLineAnimation {
    self.scanLineImageView.hidden = NO;
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.translation.y"];
    animation.fromValue = @(0);
    animation.toValue = @(self.scanRect.size.height - 3);
    animation.duration = 3.0;
    animation.repeatCount = OPEN_MAX;
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = NO;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [self.scanLineImageView.layer addAnimation:animation forKey:@"scanLineAnimation"];
}

- (void)removeScanLineAnimation {
    [self.scanLineImageView.layer removeAnimationForKey:@"scanLineAnimation"];
    self.scanLineImageView.hidden = YES;
}

#pragma mark - 扫描结果
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
    if (metadataObjects.count > 0 && metadataObjects != nil)
    {
        
        AVMetadataMachineReadableCodeObject *metadataObject = [metadataObjects firstObject];
        
        if ([metadataObject isKindOfClass:[AVMetadataMachineReadableCodeObject class]]) {
            
            NSString *scanCode = [NSString stringWithFormat:@"%@",[metadataObject stringValue]]; //扫描结果
            NSString *scanType = [NSString stringWithFormat:@"%@",[metadataObject type]]; //扫描类型
            
            if (scanCode != nil) {
                [self stopScan];
                //播放声音
                SystemSoundID soundID;
                NSString *strSoundFile = [[NSBundle mainBundle] pathForResource:@"qrcode_found" ofType:@"wav"];
                CFURLRef sound1URL = (__bridge CFURLRef)[NSURL fileURLWithPath:strSoundFile];
                AudioServicesCreateSystemSoundID(sound1URL,&soundID);
                AudioServicesPlaySystemSound(soundID);
                
                if (self.result) {
                    self.result(scanCode, scanType);
                }
            }
        }
    }

}

#pragma mark - 懒加载初始化控件

- (UIView *)maskView{
    if (!_maskView) {
        _maskView = [[UIView alloc]initWithFrame:self.bounds];
        _maskView.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5];
        UIBezierPath *fullBezierPath = [UIBezierPath bezierPathWithRect:self.bounds];
        UIBezierPath *scanBezierPath = [UIBezierPath bezierPathWithRect:self.scanRect];
        [fullBezierPath appendPath:[scanBezierPath  bezierPathByReversingPath]];
        CAShapeLayer *shapeLayer = [CAShapeLayer layer];
        shapeLayer.path = fullBezierPath.CGPath;
        _maskView.layer.mask = shapeLayer;
    }
    return _maskView;
}

- (UIImageView *)scanImageView {
    if (!_scanImageView) {
        _scanImageView = [[UIImageView alloc] initWithFrame:self.scanRect];
        _scanImageView.image = [self imageWithName:@"icon_scanbackground"];
    }
    return _scanImageView;
}

- (UIImageView *)scanLineImageView {
    if (!_scanLineImageView) {
        _scanLineImageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.scanRect.origin.x,self.scanRect.origin.y, self.scanRect.size.width, 3)];
        _scanLineImageView.image = [self imageWithName:@"icon_scanLine"];
    }
    return _scanLineImageView;
}

- (UIImage *)imageWithName:(NSString *)imageName{
    NSBundle *bundle = [NSBundle bundleForClass:[self class]];
    NSURL *url = [bundle URLForResource:@"QRCodeScanView" withExtension:@"bundle"];
    NSBundle *imageBundle = [NSBundle bundleWithURL:url];
    NSString *fileName = [NSString stringWithFormat:@"%@@2x", imageName];
    NSString *path = [imageBundle pathForResource:fileName ofType:@"png"];
    return [[UIImage imageWithContentsOfFile:path] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}

- (void)setTipLableTitle:(NSString *)text {
    if (text) {
        self.tipLabel.text = text;
    }
}

- (void)setInputButtonTitle:(NSString *)text {
    if (text) {
        [self.recordBtn setTitle:text forState:UIControlStateNormal];
        [self.recordBtn setTitle:text forState:UIControlStateHighlighted];
    }
}

//相机权限检测
- (BOOL)authorizationCheck {
    if (![self isCameraAvailable]){
//        [TipTools showAutoHideWithMessage:@"设备无相机功能，无法进行扫描"];
        return NO;
    }
    if (![self isRearCameraAvailable] && ![self isFrontCameraAvailable]) {
//        [TipTools showAutoHideWithMessage:@"设备相机错误,无法启用相机,请检查"];
        return NO;
    }
    if (![self isCameraAuthStatusCorrect]) {
//        [TipTools showAutoHideWithMessage:@"相机权限未开启,请进入系统[设置] > [隐私] > [相机] 中打开开关"];
        return NO;
    }
    return YES;
}

- (BOOL)isCameraAvailable{
    return [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
}

- (BOOL)isFrontCameraAvailable{
    return [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront];
}

- (BOOL)isRearCameraAvailable{
    return [UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear];
}

- (BOOL)isCameraAuthStatusCorrect{
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if (authStatus == AVAuthorizationStatusAuthorized || authStatus == AVAuthorizationStatusNotDetermined) {
        return YES;
    }
    return NO;
}


@end
